package com.douqu.game.core.entity.world.map;

import com.bean.core.buffer.ByteBuffer;
import com.bean.core.util.Utils;
import com.douqu.game.core.config.FunctionConfig;
import com.douqu.game.core.config.StableDataConfig;
import com.douqu.game.core.config.map.*;
import com.douqu.game.core.controller.PlayerController;
import com.douqu.game.core.e.*;
import com.douqu.game.core.entity.db.DB;
import com.douqu.game.core.factory.*;
import com.douqu.game.core.protobuf.SGCommonProto;
import com.douqu.game.core.protobuf.SGMainProto;
import com.douqu.game.core.protobuf.SGPlayerProto;
import com.douqu.game.core.protobuf.SGSystemProto;
import com.douqu.game.core.util.LogUtils;
import com.douqu.game.core.util.SendUtils;
import com.douqu.game.core.util.StringUtils;
import com.douqu.game.core.util.time.TimeUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @Author: Bean
 * @Description:
 * @Date: 2018-04-16 11:06
 */
public class CityBean extends DB
{
    /**
     * 临时增量ID
     */
    private int tempId;
    /**
     *  玩家流水号
     *　只有单人战场这个字段才有值
     */
    private String masterPlayerIndex;
    /**
     * 是否在刷新中
     */
    private boolean garrisonRefreshing = false;

    /** 当前状态 */
    private SGCommonProto.E_CITY_STATUS status;

    /**
     * 最后更新状态时间
     */
    private long lastUpdateStatusTime;

    /** 所属阵营 */
    public int camp;

    /**
     * 驻军列表(属于防守方)
     */
    private List<SpriteGarrisonBean> spriteGarrisonList = new CopyOnWriteArrayList<>();

    /**
     * 远征军
     */
    private List<SpriteExpeditionBean> spriteExpeditionList = new CopyOnWriteArrayList<>();

    /**
     * 所有在这个城的
     */
    private List<SpritePlayerBean> spritePlayerList = new CopyOnWriteArrayList<>();

    /**
     * 所有对象，包含驻军，玩家，远征军
     */
    private Map<String, SpriteBean> spriteBeanMap = new ConcurrentHashMap<>();

    /**
     * 正在查看这个城的玩家(不存数据库)
     */
    private List<String> lookPlayerList = new CopyOnWriteArrayList<>();

    /**
     * 攻方战斗胜利
     */
    private OccupyCityParam occupyCityParam;

    /**
     * 城市奖励情况
     */
    private CityDropData cityDropData;

    public CityBean(String masterPlayerIndex)
    {
        super(DataFactory.CITY_KEY);

        this.status = SGCommonProto.E_CITY_STATUS.CITY_STATUS_PEACE;
        this.lastUpdateStatusTime = DataFactory.currentTime == 0 ? System.currentTimeMillis() : DataFactory.currentTime;
        this.masterPlayerIndex = masterPlayerIndex;
        cityDropData = new CityDropData();
    }

    public CityBean(int id, int camp, String masterPlayerIndex)
    {
        super(DataFactory.CITY_KEY, id);

        this.camp = camp;
        this.status = SGCommonProto.E_CITY_STATUS.CITY_STATUS_PEACE;
        this.lastUpdateStatusTime = DataFactory.currentTime == 0 ? System.currentTimeMillis() : DataFactory.currentTime;
        this.masterPlayerIndex = masterPlayerIndex;
        cityDropData = new CityDropData();
    }

    @Override
    public void reset() {

    }

    @Override
    public void loadFrom(ByteBuffer buffer)
    {
        super.loadFrom(buffer);

        camp = buffer.readByte();

        SpritePlayerBean playerBean = null;

        spritePlayerList.clear();

        int size = buffer.readShort();
        for(int i = 0; i < size; i++)
        {
            playerBean = new SpritePlayerBean(masterPlayerIndex);
            playerBean.loadFrom(buffer);
            //后续初始化队伍和城的一些操作放在WorldManager里面统一处理

            playerBean.setActionPlayerType(E_ActionPlayerType.OFFLINE, 0);

            spritePlayerList.add(playerBean);
            spriteBeanMap.put(playerBean.getObjectIndex(), playerBean);
        }

        //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++远征军新增的
        size = buffer.readInt();
        SpriteExpeditionBean spriteExpeditionBean = null;
        for(int i = 0; i < size; i++)
        {
            spriteExpeditionBean = new SpriteExpeditionBean();
            spriteExpeditionBean.loadFrom(buffer);
            //后续初始化队伍和城的一些操作放在WorldManager里面统一处理

            spriteExpeditionList.add(spriteExpeditionBean);
            spriteBeanMap.put(spriteExpeditionBean.getObjectIndex(), spriteExpeditionBean);
        }
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    }

    @Override
    public void writeTo(ByteBuffer buffer)
    {
        super.writeTo(buffer);

        buffer.writeByte(camp);

        if(getConfig().type != SGCommonProto.E_CITY_TYPE.CITY_TYPE_CAPITAL_VALUE)
        {
            buffer.writeShort(spritePlayerList.size());
            for(SpriteBean spriteBean : spritePlayerList)
            {
                spriteBean.writeTo(buffer);
            }
        }
        else
        {
            buffer.writeShort(0);//主城里的玩家不存储数据
        }

        //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++远征军新增的
        int size = spriteExpeditionList.size();
        buffer.writeInt(size);
        for(SpriteExpeditionBean spriteExpeditionBean : spriteExpeditionList)
        {
            spriteExpeditionBean.writeTo(buffer);
        }
        //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    }

    /**
     * 刷新驻军
     */
    public void initGarrison(E_CityInitGarrisonType... type)
    {
        if(status != SGCommonProto.E_CITY_STATUS.CITY_STATUS_PEACE)
            return;

        if(!getConfig().canBattle)
            return;

        if(type.length > 0 && type[0] != E_CityInitGarrisonType.SERVER_START)
            LogUtils.warn("城 -> " + getConfig().name + " 重新初始化驻军 -> " + type[0]);

        garrisonRefreshing = true;

        WorldMapData worldMapData = WorldInfoFactory.getInstance().getWorldMapData(masterPlayerIndex);
        final int averageLv = worldMapData.getPlayerAverageLevel();

        CityConfig cityConfig = getConfig();
        if(camp == 0) camp = cityConfig.camp;
        List<CityArmyConfig> cityArmyConfigList = DataFactory.getInstance().getDataList(DataFactory.CITY_ARMY_KEY);
        int armyId = 0, finalLv = 0, finalGroup = 0, armyGroupId = 0;
        for(CityArmyConfig cityArmyConfig : cityArmyConfigList)
        {
            if(cityArmyConfig.type == cityConfig.stationedArmy && cityArmyConfig.camp == camp)
            {
                if(Utils.isNullOrEmpty(masterPlayerIndex))//世界大地图
                {
                    if(cityArmyConfig.grade != ConstantFactory.CITY_ARMY_GRADE_WORLD)
                        continue;
                }
                else
                {//新手大地图
                    if(cityArmyConfig.grade != ConstantFactory.CITY_ARMY_GRADE_ROOKIE)
                        continue;
                }
                armyId = cityArmyConfig.id;
                finalLv = averageLv + cityArmyConfig.lvAuxiliary;
                finalLv = finalLv < 1 ? 1 : finalLv;
                finalGroup = cityArmyConfig.group;
                break;
            }
        }

        if(worldMapData.isSingle())
            finalLv = finalLv < 1 ? 1 : finalLv;
        else
            finalLv = finalLv < worldMapData.getMinPlayerAverageLevel() ? worldMapData.getMinPlayerAverageLevel() : finalLv;

//        LogUtils.debug("finalLv -> " + finalLv + " finalGroup -> " + finalGroup + " averageLv -> " + averageLv);

        List<CityArmyGroupConfig> cityArmyGroupConfigList = DataFactory.getInstance().getDataList(DataFactory.CITY_ARMY_GROUP_KEY);
        for(CityArmyGroupConfig cityArmyGroupConfig : cityArmyGroupConfigList)
        {
            if(cityArmyGroupConfig.group == finalGroup && finalLv == cityArmyGroupConfig.getLv())
            {
                armyGroupId = cityArmyGroupConfig.id;
                break;
            }
        }

        for(SpriteGarrisonBean spriteGarrisonBean : spriteGarrisonList)
        {
            WorldInfoFactory.getInstance().addInOutCityRecord(getConfig().name, spriteGarrisonBean.getObjectIndex()+"-"+spriteGarrisonBean.getName(), E_CityInOutType.OUT_RESET_GARRISON, !Utils.isNull(masterPlayerIndex));
            spriteBeanMap.remove(spriteGarrisonBean.getObjectIndex());
        }
        spriteGarrisonList.clear();

        int count = cityConfig.armyMaxCount;
        SpriteGarrisonBean spriteGarrisonBean = null;
        for(int i = 0; i < count; i++)
        {
            spriteGarrisonList.add(spriteGarrisonBean = new SpriteGarrisonBean(++tempId, armyId, armyGroupId, camp, id, masterPlayerIndex));
            spriteBeanMap.put(spriteGarrisonBean.getObjectIndex(), spriteGarrisonBean);
        }

        garrisonRefreshing = false;

//        LogUtils.debug("初始化驻军 -> " + cityConfig.id + "-" + cityConfig.name + "-" + spriteGarrisonList);
    }

    /**
     * 生成远征军
     * @param cityArmyConfig
     * @param expeditionConfig
     */
    public int initExpedition(CityArmyConfig cityArmyConfig, CityExpeditionConfig expeditionConfig, int[] routeList)
    {
        LogUtils.debug(getConfig().name + "   开始生成远征军 -> " + cityArmyConfig + " expeditionConfig:" + expeditionConfig.name);
        WorldMapData worldMapData = WorldInfoFactory.getInstance().getWorldMapData(masterPlayerIndex);
        final int averageLv = worldMapData.getPlayerAverageLevel();

        int finalLv = averageLv + cityArmyConfig.lvAuxiliary;
        finalLv = finalLv < 1 ? 1 : finalLv;

        int armyGroupId = 0;
        List<CityArmyGroupConfig> cityArmyGroupConfigList = DataFactory.getInstance().getDataList(DataFactory.CITY_ARMY_GROUP_KEY);
        for(CityArmyGroupConfig cityArmyGroupConfig : cityArmyGroupConfigList)
        {
            if(cityArmyGroupConfig.group == cityArmyConfig.group && finalLv == cityArmyGroupConfig.getLv())
            {
                armyGroupId = cityArmyGroupConfig.id;
                break;
            }
        }

        SpriteExpeditionBean spriteExpeditionBean = null;
        SGCommonProto.E_ARMY_STATUS expeditionStatus = null;
        if(status == SGCommonProto.E_CITY_STATUS.CITY_STATUS_PEACE)
        {
            expeditionStatus = routeList.length == 1 ? SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_FREE : SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MOVE;
        }
        else
        {
            expeditionStatus = SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH;
        }
        SGCommonProto.E_ARMY_TEAM expeditionTeam = worldMapData.isAlly(cityArmyConfig.camp, camp) ? SGCommonProto.E_ARMY_TEAM.ARMY_TEAM_DEF : SGCommonProto.E_ARMY_TEAM.ARMY_TEAM_ATK;
        long endTime = DataFactory.currentTime + expeditionConfig.startTime.getKeepTime(TimeUtils.MILLISECOND);
        for(int i = 0; i < expeditionConfig.count; i++)
        {
            spriteExpeditionList.add(spriteExpeditionBean = new SpriteExpeditionBean(++tempId, cityArmyConfig.id, armyGroupId, id, routeList, expeditionTeam, expeditionStatus, endTime));
            spriteBeanMap.put(spriteExpeditionBean.getObjectIndex(), spriteExpeditionBean);
        }

//        LogUtils.info("远征军生成成功========================结束时间:" + com.bean.core.util.TimeUtils.getFormatTime(endTime));
        return finalLv;
    }

    public void update(WorldMapUpdateResult updateResult)
    {
        //异常处理
        boolean isError = false;
        for(SpriteBean spriteBean : spriteGarrisonList)
        {
            if(spriteBean.isBattleOrPrepare() && spriteBean.isOverdueStatus(360000))
            {
                LogUtils.error(spriteBean.getObjectIndex() + "-" + spriteBean.getName() + " 处于战斗状态超过6分钟，自动设置回匹配状态!");
                spriteBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH);
                isError = true;
            }
        }

        WorldMapData worldMapData = WorldInfoFactory.getInstance().getWorldMapData(masterPlayerIndex);
        for(SpriteExpeditionBean spriteExpeditionBean : spriteExpeditionList)
        {
            if(spriteExpeditionBean.isBattleOrPrepare() && spriteExpeditionBean.isOverdueStatus(360000))
            {
                LogUtils.error(spriteExpeditionBean.getObjectIndex() + "-" + spriteExpeditionBean.getName() + " 处于战斗状态超过6分钟，自动设置回匹配状态!");
                spriteExpeditionBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH);
                isError = true;
            }
        }

        for(SpritePlayerBean spritePlayerBean : spritePlayerList)
        {
            if((spritePlayerBean.isBattleOrPrepare()) && spritePlayerBean.isOverdueStatus(360000))
            {
                if(spritePlayerBean.isAttacker())
                {
                    LogUtils.error(spritePlayerBean.getObjectIndex() + "-" + spritePlayerBean.getName() + " 处于战斗状态超过6分钟，攻击方自动设置回待命状态!");
                    spritePlayerBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_WAIT);
                }
                else
                {
                    LogUtils.error(spritePlayerBean.getObjectIndex() + "-" + spritePlayerBean.getName() + " 处于战斗状态超过6分钟，防守方自动设置回空闲状态!");
                    spritePlayerBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_FREE);
                }
                isError = true;
            }
        }

        if(isError)
        {
            LogUtils.error("城 -> " + getConfig().name + " 有异常,现在重新检测状态");
            checkCityStatus();
        }

        if(occupyCityParam != null && occupyCityParam.isOverdue())
        {
            LogUtils.debug("城 -> " + id + " 被 " + occupyCityParam.getWinner().getObjectIndex() + " 占领，之前的阵营:" + camp + " 现在的阵营 -> " + occupyCityParam.getWinner().camp);
            camp = occupyCityParam.getWinner().camp;
            updateResult.addOccupyCity(id, occupyCityParam);

            LogUtils.debug(" worldMapData isSingle -> " + worldMapData.isSingle());

            //占领成功，如果这时攻方列表中有跟占领者不是联盟阵营的人
            for(SpritePlayerBean spriteBean : spritePlayerList)
            {
                if(spriteBean.isRemove() || spriteBean.isDie())
                    continue;

                if(worldMapData.isAlly(spriteBean.camp, camp))
                {
                    spriteBean.setTeam(SGCommonProto.E_ARMY_TEAM.ARMY_TEAM_DEF);
                    spriteBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_FREE);
                }
                else
                {
                    spriteBean.setTeam(SGCommonProto.E_ARMY_TEAM.ARMY_TEAM_ATK);
                    spriteBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_WAIT);
                }
            }

            for(SpriteExpeditionBean spriteExpeditionBean : spriteExpeditionList)
            {
                if(spriteExpeditionBean.isRemove() || spriteExpeditionBean.isDie())
                    continue;

                if(worldMapData.isAlly(spriteExpeditionBean.camp, camp))
                {
                    spriteExpeditionBean.setTeam(SGCommonProto.E_ARMY_TEAM.ARMY_TEAM_DEF);
                    spriteExpeditionBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_FREE);
                }
                else
                {
                    spriteExpeditionBean.setTeam(SGCommonProto.E_ARMY_TEAM.ARMY_TEAM_ATK);
                    spriteExpeditionBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_WAIT);
                }
            }

            setStatus(SGCommonProto.E_CITY_STATUS.CITY_STATUS_PEACE);
            sendOccupyInfo(occupyCityParam);

            occupyCityParam = null;
        }

        List<SGCommonProto.ArmyQueueChange> changeList = new ArrayList<>();

        for(SpritePlayerBean spriteBean : spritePlayerList)
        {
            spriteBean.update(updateResult);

            spriteBean.checkRemove();

            if(spriteBean.isRemove())
            {
                updateResult.addRemoveSprite(id, spriteBean);
                if(spriteBean.isMatch())
                    changeList.add(SendUtils.createChangeQueue(SGCommonProto.E_QUEUE_CHANGE.QUEUE_CHANGE_OUT, SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH, spriteBean.getTeam(), spriteBean));
                else if(spriteBean.isBattleOrPrepare())
                    changeList.add(SendUtils.createChangeQueue(SGCommonProto.E_QUEUE_CHANGE.QUEUE_CHANGE_OUT, SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_BATTLE, spriteBean.getTeam(), spriteBean));
                continue;
            }

            checkStatus(spriteBean, updateResult, changeList);
        }

        for(SpriteExpeditionBean spriteExpeditionBean : spriteExpeditionList)
        {
            if(spriteExpeditionBean.isRemove())
            {
                if(spriteExpeditionBean.isFree() || spriteExpeditionBean.isMove() || spriteExpeditionBean.isWait() || spriteExpeditionBean.isMatch())
                {
                    LogUtils.debug("删除到期并且恢复到空闲状态的远征军 -> " + spriteExpeditionBean);
                    updateResult.addRemoveSprite(id, spriteExpeditionBean);

                    if(spriteExpeditionBean.isMatch())
                        changeList.add(SendUtils.createChangeQueue(SGCommonProto.E_QUEUE_CHANGE.QUEUE_CHANGE_OUT,
                                SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH, spriteExpeditionBean.getTeam(), spriteExpeditionBean));
                }
                continue;
            }
            else
            {
                if(spriteExpeditionBean.isEnd())
                {
                    LogUtils.debug("准备删除到期远征军 -> " + spriteExpeditionBean + "  cityId:" + id);
                    //持续时间到了要删除
                    spriteExpeditionBean.setRemove(true);//表示为remove,保证不会再进入战斗
                    if(spriteExpeditionBean.isFree() || spriteExpeditionBean.isMove() || spriteExpeditionBean.isWait() || spriteExpeditionBean.isMatch())
                    {
                        updateResult.addRemoveSprite(id, spriteExpeditionBean);

                        if(spriteExpeditionBean.isMatch())
                            changeList.add(SendUtils.createChangeQueue(SGCommonProto.E_QUEUE_CHANGE.QUEUE_CHANGE_OUT,
                                    SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH, spriteExpeditionBean.getTeam(), spriteExpeditionBean));
                    }
                    continue;
                }
            }

            checkStatus(spriteExpeditionBean, updateResult, changeList);

            spriteExpeditionBean.update(updateResult);
        }

        if(!changeList.isEmpty())
        {
            SendUtils.sendChangeQueue(this, changeList);
        }
    }


    public void checkStatus(SpriteBean spriteBean, WorldMapUpdateResult updateResult, List changeList)
    {
        if(spriteBean instanceof SpriteGarrisonBean)
            return;

        WorldMapData worldMapData = WorldInfoFactory.getInstance().getWorldMapData(masterPlayerIndex);

        if(getConfig().canBattle)
        {
            //待命状态超时，加入队列中
            if(spriteBean.isOverWait())
            {
                SGCommonProto.E_CITY_STATUS beforeStatus = status;

                in(spriteBean, false, false);

                if(beforeStatus == status)
                    changeList.add(SendUtils.createChangeQueue(SGCommonProto.E_QUEUE_CHANGE.QUEUE_CHANGE_IN, spriteBean.getStatus(), spriteBean.getTeam(), spriteBean));
            }
            else if(spriteBean.isMatch())
            {
                //是否是手动匹配
                boolean isManualMatch = spriteBean instanceof SpritePlayerBean && ((SpritePlayerBean) spriteBean).isManualMatch();
                if(spriteBean.isOverdueStatus() && !spriteBean.isInProtectTime() || isManualMatch)
                {
                    String targetIndex = spriteBean instanceof SpritePlayerBean ? ((SpritePlayerBean) spriteBean).getManualMatchPlayerIndex() : null;
                    //开始匹配
                    MapMatchTeam mapMatchTeam = matchTeam(spriteBean, targetIndex);
                    if(mapMatchTeam != null)
                    {
                        setStatus(SGCommonProto.E_CITY_STATUS.CITY_STATUS_BATTLE);

                        LogUtils.debug((isManualMatch?"手动":"自动") + "匹配战斗 -> " + mapMatchTeam + " battleDetailType:" + mapMatchTeam.getBattleDetailType());
                        //添加到匹配组列表中，用来检测
                        worldMapData.addMatchTeam(mapMatchTeam);
                        //添加到更新结果中，用来发送给玩家匹配成功的消息
                        SendUtils.sendMapChallenge(mapMatchTeam);
                        //添加队列改变消息
                        changeList.addAll(SendUtils.createChangeQueueList(mapMatchTeam));
                    }
                    else
                    {
                        if(isManualMatch && Utils.isNull(targetIndex))
                        {//手动点快速匹配，没有匹配到，发送错误提示
                            spriteBean.sendWarn(WordFactory.MAP_MATCH_NO_TARGET);
                        }
                        spriteBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH);
                    }

                    if(spriteBean instanceof SpritePlayerBean)
                    {
                        ((SpritePlayerBean) spriteBean).setManualMatch(false, null);
                    }
                }
            }
            else if(spriteBean.isFree())
            {
                //检查异常数据
                if(spriteBean.getTeam() == SGCommonProto.E_ARMY_TEAM.ARMY_TEAM_UNKNOWN)
                {
                    if(worldMapData.isAlly(spriteBean.camp, camp))
                        spriteBean.setTeam(SGCommonProto.E_ARMY_TEAM.ARMY_TEAM_DEF);
                    else
                        spriteBean.setTeam(SGCommonProto.E_ARMY_TEAM.ARMY_TEAM_ATK);
                }
                else if(spriteBean.isAttacker())
                {
                    spriteBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_WAIT);
                }
            }
            else if(spriteBean.isDie() && spriteBean instanceof SpritePlayerBean)
            {
                boolean overdue = false;
                StableDataConfig stableDataConfig = DataFactory.getInstance().getGameObject(DataFactory.STABLE_DATA_KEY, E_StableDataType.REVIVE_TIME.getCode());
                if(stableDataConfig == null && spriteBean.isOverdueStatus()){
                    overdue = true;
                }else if(stableDataConfig != null && spriteBean.isOverdueStatus(stableDataConfig.intValue*1000 + 5000)){
                    overdue = true;
                }

                if(overdue)
                {
                    //死亡选择时间到了还没选择，送回主城
                    WorldInfoFactory.getInstance().getWorldMapData(masterPlayerIndex).backMainCity(spriteBean, SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_RECOVER, true);
                    updateResult.addRecoverPlayer((SpritePlayerBean) spriteBean);
                    checkCityStatus();
                }
            }
            checkDefStatus();
        }

        //恢复状态
        if(spriteBean instanceof SpritePlayerBean)
        {
            SpritePlayerBean spritePlayerBean = (SpritePlayerBean) spriteBean;
            if(spritePlayerBean.isRecover())
            {
                spritePlayerBean.onceRecover();
                //检测状态超时
                if(spritePlayerBean.getBattleTemp().isFull())
                {
                    spritePlayerBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_FREE);
                }
            }
        }
    }

    /**
     * 复活
     * @param spriteBean
     */
    public void revive(SpriteBean spriteBean)
    {
        if(spriteBean.getStatus() != SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_DIE || spriteBeanMap.get(spriteBean.getObjectIndex()) == null)
        {
            LogUtils.error("复活错误");
            return;
        }

        WorldMapData worldMapData = WorldInfoFactory.getInstance().getWorldMapData(masterPlayerIndex);
        spriteBean.setTeam(worldMapData.isAlly(spriteBean.camp, camp) ? SGCommonProto.E_ARMY_TEAM.ARMY_TEAM_DEF : SGCommonProto.E_ARMY_TEAM.ARMY_TEAM_ATK);

        CityConfig cityConfig = getConfig();
        if(cityConfig.canBattle)
        {
            if(spriteBean.isDefender())
            {
                //防御方，状态为空闲
                if(isHaveAttacker())
                    spriteBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_WAIT);
                else
                    spriteBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_FREE);
            }
            else
            {
                //非联盟的城，设置为攻击方，状态为待命
                spriteBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_WAIT);
            }
        }
        else
        {
            if(cityConfig.type != SGCommonProto.E_CITY_TYPE.CITY_TYPE_CAPITAL_VALUE)
            {
                //不是主城，不能战斗的城，设置为空闲状态
                spriteBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_FREE);
            }
        }
    }
    /**
     * 进城
     * @param spriteBean
     */
    public void arrive(SpriteBean spriteBean, boolean stop, E_CityInOutType type)
    {
        if(spriteBean instanceof SpriteGarrisonBean)
            return;

        LogUtils.debug(spriteBean.getName() +  "  到达城 -> " + getConfig().name);
        if(spriteBeanMap.get(spriteBean.getObjectIndex()) != null)
        {
            LogUtils.error("城-> " + this);
            LogUtils.error("城里已经有这个玩家了 -> " + spriteBean.getName() + " " + id + " " + spriteBean.getObjectIndex());
            return;
        }

        WorldMapData worldMapData = WorldInfoFactory.getInstance().getWorldMapData(masterPlayerIndex);
        boolean isAlly = worldMapData.isAlly(spriteBean.camp, camp);
        spriteBean.setTeam(isAlly ? SGCommonProto.E_ARMY_TEAM.ARMY_TEAM_DEF : SGCommonProto.E_ARMY_TEAM.ARMY_TEAM_ATK);

        CityConfig cityConfig = getConfig();
        if(cityConfig.canBattle)
        {
            if(isAlly)
            {
                //联盟的城，设置为防御方，状态为空闲
                if(stop)
                {
                    if(isHaveAttacker())
                        spriteBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_WAIT);
                    else
                        spriteBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_FREE);
                }
            }
            else
            {
                //非联盟的城，设置为攻击方，状态为待命
                spriteBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_WAIT);
            }
        }
        else
        {
            if(stop)
                spriteBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_FREE);
//            if(cityConfig.type != SGCommonProto.E_CITY_TYPE.CITY_TYPE_CAPITAL_VALUE)
//            {
//                //不是主城，不能战斗的城，设置为空闲状态
//                spriteBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_FREE);
//            }
        }

        spriteBean.setCurCity(id);

        if(spriteBean instanceof SpritePlayerBean)
            spritePlayerList.add((SpritePlayerBean) spriteBean);
        else if(spriteBean instanceof  SpriteExpeditionBean)
            spriteExpeditionList.add((SpriteExpeditionBean) spriteBean);

        spriteBeanMap.put(spriteBean.getObjectIndex(), spriteBean);

        WorldInfoFactory.getInstance().addInOutCityRecord(getConfig().name, spriteBean.getObjectIndex() + "-" + spriteBean.getName(), type, !Utils.isNull(masterPlayerIndex));

        LogUtils.debug(spriteBean.getName() + " 到达城完成 -> " + getConfig().name + "　　当前城数据 ->" + this);
//        LogUtils.debug(worldMapData.getSpriteBeanCityMap());
    }

    /**
     * 进城
     * @param spriteBean
     * @param active 是否主动进城
     */
    public void in(SpriteBean spriteBean, boolean active, boolean sendChangeQueue)
    {
        //进城后城状态变了(通知),进城后城状态不变
        //1.攻击方主动进城 2.攻击方时间到了进城 3.防守方主动进城 4.防守方时间到了进城
        if(active || lookPlayerList.contains(spriteBean.getObjectIndex()))
        {
            //查看自己所在城不算进城，但是会装进查看列表里，所以进城时要检测自己是否在查看列表里，如果在则表示inCity
//            LogUtils.debug("已经在查看这个城了--------------" + id);
            spriteBean.setInCity(true);
            WorldInfoFactory.getInstance().getWorldMapData(masterPlayerIndex).removeLookCity(spriteBean.getObjectIndex());
        }

        //1.手动点进城 2.查看自己所在城的详情 3.待命时间到了自动进城
        if(!spriteBean.isWait() && !spriteBean.isFree())
        {
//            LogUtils.warn("进城错误 ,当前状态 -> " + spriteBean.getStatus());
            return;
        }

        LogUtils.debug("进城 -> " + spriteBean.getName() + "(" + spriteBean.getObjectIndex() + ")" + "  id -> " + id + "  inCity -> " + spriteBean.isInCity());

        spriteBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH);

        if(status == SGCommonProto.E_CITY_STATUS.CITY_STATUS_PEACE)
        {
            if(spriteBean.isAttacker())
            {
                setStatus(SGCommonProto.E_CITY_STATUS.CITY_STATUS_BATTLE);
                checkDefStatus();
            }
        }
        else if(status == SGCommonProto.E_CITY_STATUS.CITY_STATUS_TRANSITION)
        {
            //如果是在占领中进城
            if(spriteBean.isDefender())
            {
                for(SpriteBean spritePlayerBean : spritePlayerList)
                {
                    if(spritePlayerBean.isAttacker())
                    {
                        //攻击方的要从战斗中回到队列中
                        spritePlayerBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH);
                    }
                }

                for(SpriteBean spriteExpeditionBean : spriteExpeditionList)
                {
                    if(spriteExpeditionBean.isAttacker())
                    {
                        //攻击方的要从战斗中回到队列中
                        spriteExpeditionBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH);
                    }
                }

                setStatus(SGCommonProto.E_CITY_STATUS.CITY_STATUS_BATTLE);
                setOccupyCityParam(null);
            }
        }
        else
        {
            if(sendChangeQueue)
            {
                SendUtils.sendChangeQueue(this, SendUtils.createChangeQueue(SGCommonProto.E_QUEUE_CHANGE.QUEUE_CHANGE_IN, SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH, spriteBean.getTeam(), spriteBean), spriteBean.getObjectIndex());
            }
        }
    }
    /**
     * 离开城
     * @param spriteBean
     */
    public void leave(SpriteBean spriteBean, SpriteBean winner, E_CityInOutType type)
    {
        WorldMapData worldMapData = WorldInfoFactory.getInstance().getWorldMapData(masterPlayerIndex);

        if(spriteBean instanceof SpritePlayerBean)
        {
            ((SpritePlayerBean) spriteBean).checkInitCard();
        }

        List<SGCommonProto.ArmyQueueChange> changeList = new ArrayList<>();

        //如果是正在队列中或者战斗中离开城，要通知队列变化
        if(spriteBean.isMatch())
            changeList.add(SendUtils.createChangeQueue(SGCommonProto.E_QUEUE_CHANGE.QUEUE_CHANGE_OUT, SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH, spriteBean.getTeam(), spriteBean));
        else if(spriteBean.isBattleOrPrepare())
            changeList.add(SendUtils.createChangeQueue(SGCommonProto.E_QUEUE_CHANGE.QUEUE_CHANGE_OUT, SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_BATTLE, spriteBean.getTeam(), spriteBean));

        if(winner == null || !(spriteBean instanceof SpritePlayerBean))
        {
            spriteBean.setTeam(SGCommonProto.E_ARMY_TEAM.ARMY_TEAM_UNKNOWN);
            worldMapData.removeSprite(spriteBean, this, false, type);
        }

        if(winner != null)
        {
            //winner不为空表示是战斗失败后从城里离开
            if(spriteBean instanceof SpritePlayerBean)
            {
                spriteBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_DIE);
            }

            if(winner instanceof SpritePlayerBean || winner instanceof SpriteExpeditionBean)
            {
                if(winner.isAttacker())
                {
                    if(!isHaveDefender())
                    {
                        //防守方没人了，等待占领
                        setOccupyCityParam(new OccupyCityParam(DataFactory.currentTime, camp, winner, spriteBean));
                        setStatus(SGCommonProto.E_CITY_STATUS.CITY_STATUS_TRANSITION);
                    }
                    else
                    {
                        //防守方还有人，重新进入待命
                        winner.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH);
                        winner.setStartProtectTime(DataFactory.currentTime);
                    }
                }
                else if(winner.isDefender())
                {
                    if(!isHaveAttacker())
                    {
                        //攻击方没人了，防守方全部进入空闲
                        initDefenderFree();
                    }
                    else
                    {
                        //攻击方还有人，重新进入待命
                        winner.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH);
                        winner.setStartProtectTime(DataFactory.currentTime);
                    }
                }
            }
            else if(winner instanceof SpriteGarrisonBean)
            {
                if(!isHaveAttacker())
                {
                    //攻击方没人了，防守方全部进入空闲
                    initDefenderFree();
                }
                //守军没有待命状态，重新进入队列
                winner.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH);
            }

            changeList.add(SendUtils.createChangeQueue(SGCommonProto.E_QUEUE_CHANGE.QUEUE_CHANGE_OUT, SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_BATTLE, winner.getTeam(), winner));
            if(winner.isMatch())
            {
                changeList.add(SendUtils.createChangeQueue(SGCommonProto.E_QUEUE_CHANGE.QUEUE_CHANGE_IN, SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH, winner.getTeam(), winner));
            }
        }

//        LogUtils.debug("changeList -> " + changeList);

        SGCommonProto.E_CITY_STATUS beforeStatus = status;

        checkCityStatus(spriteBean);

        if(beforeStatus == status)
        {
            SendUtils.sendChangeQueue(this, changeList);
        }

        if(winner == null)
        {
            //离开城的时候因为玩家还没有加入到任何一个城里，所以只能单独发送城状态信息
            SendUtils.sendCityStatus(this, spriteBean);
//            worldMapData.removeSpriteCurCity(spriteBean.getObjectIndex());
        }

        LogUtils.debug(spriteBean.getName() + " 离开城->" + getConfig().name + "  现在城数据:" + this);
    }

    private void initDefenderFree()
    {
        for(SpriteBean defender : spritePlayerList)
        {
            if(defender.isRemove() || defender.isDie())
                continue;

            if(defender.isDefender())
                defender.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_FREE);
        }

        for(SpriteBean defender : spriteExpeditionList)
        {
            if(defender.isRemove() || defender.isDie())
                continue;

            if(defender.isDefender())
                defender.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_FREE);
        }
    }



    /**
     * 获取对象
     * @param objectIndex
     * @return
     */
    public SpriteBean getSpriteBean(String objectIndex)
    {
        return spriteBeanMap.get(objectIndex);
    }


    public synchronized MapMatchTeam matchTeam(SpriteBean spriteBean, String targetIndex)
    {
        if(spriteBean.getStatus() != SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH)
            return null;

        SpriteBean target = null;
        if(!Utils.isNull(targetIndex))
        {
            //手动挑战指定玩家
            target = getSpriteBean(targetIndex);
            if(target == null || target.isRemove() || !target.isMatch() || target.isInProtectTime() || target.getTeam() == spriteBean.getTeam())
                return null;

            LogUtils.debug("手动挑战指定对手 -> " + target);
        }
        else
        {
            if(spriteBean.isAttacker())
            {
                //玩家是攻城方
                target = getRandomDefenderTarget();
                if(target != null)
                {
                    LogUtils.debug("攻城方匹配到守城方 -> " + target);
                }
            }
            else if(spriteBean.isDefender())
            {
                //玩家是守城方
                target = getRandomAttackTarget();
                if(target != null)
                {
                    LogUtils.debug("守城方匹配到攻城方 -> " + target);
                }
            }
        }

        MapMatchTeam result = null;
        if(target != null)
        {
            if(!target.isMatch())
                return null;

            if(spriteBean.isInCity() || target instanceof SpriteGarrisonBean || target instanceof SpriteExpeditionBean)
                result = new MapMatchTeam(spriteBean, target, ConfigFactory.WORLD_MAP_BATTLE_WAIT_TIME, id, DataFactory.getInstance().getMapIdByWorldMap(camp));
            else
                result = new MapMatchTeam(target, spriteBean, ConfigFactory.WORLD_MAP_BATTLE_WAIT_TIME, id, DataFactory.getInstance().getMapIdByWorldMap(camp));
        }

        return result;
    }

    public SpriteBean getRandomDefenderTarget()
    {
        if(garrisonRefreshing)
            return null;

        List<SpriteBean> tempList = new ArrayList<>();
        for(SpriteBean spriteBean : spritePlayerList)
        {
            if(spriteBean.isRemove() || spriteBean.isDie())
                continue;

            if(spriteBean.isDefender() && spriteBean.isMatch() && !spriteBean.isInProtectTime())
            {
                tempList.add(spriteBean);
            }
        }

        for(SpriteGarrisonBean spriteGarrisonBean : spriteGarrisonList)
        {
            if(spriteGarrisonBean.isMatch())
            {
                tempList.add(spriteGarrisonBean);
            }
        }

        for(SpriteExpeditionBean spriteExpeditionBean : spriteExpeditionList)
        {
            if(spriteExpeditionBean.isRemove() || spriteExpeditionBean.isDie())
                continue;

            if(spriteExpeditionBean.isDefender() && spriteExpeditionBean.isMatch() && !spriteExpeditionBean.isInProtectTime())
            {
                tempList.add(spriteExpeditionBean);
            }
        }

        int size = tempList.size();
        return size == 0 ? null : tempList.get(Utils.getRandom(size));
    }

    public SpriteBean getRandomAttackTarget()
    {
        if(garrisonRefreshing)
            return null;

        List<SpriteBean> tempList = new ArrayList<>();
        for(SpriteBean spriteBean : spritePlayerList)
        {
            if(spriteBean.isRemove() || spriteBean.isDie())
                continue;

            if(spriteBean.isAttacker() && spriteBean.isMatch() && !spriteBean.isInProtectTime())
            {
                tempList.add(spriteBean);
            }
        }

        for(SpriteBean spriteBean : spriteExpeditionList)
        {
            if(spriteBean.isRemove() || spriteBean.isDie())
                continue;

            if(spriteBean.isAttacker() && spriteBean.isMatch() && !spriteBean.isInProtectTime())
            {
                tempList.add(spriteBean);
            }
        }

        int size = tempList.size();
        return size == 0 ? null : tempList.get(Utils.getRandom(size));
    }



    /**
     * 获取防御方数量
     * @return
     */
    public boolean isHaveDefender()
    {
        for(SpriteBean spriteBean : spritePlayerList)
        {
            if(spriteBean.isDefender())
            {
                if(spriteBean.isBattleOrPrepare() || spriteBean.isMatch())
                    return true;
            }
        }
        for(SpriteBean spriteBean : spriteExpeditionList)
        {
            if(spriteBean.isDefender())
            {
                if(spriteBean.isBattleOrPrepare() || spriteBean.isMatch())
                    return true;
            }
        }
        return spriteGarrisonList.size() > 0;
    }

    /**
     * 获取攻击方数量
     * @return
     */
    public boolean isHaveAttacker()
    {
        for(SpriteBean spriteBean : spritePlayerList)
        {
            if(spriteBean.isAttacker())
            {
                if(spriteBean.isBattleOrPrepare() || spriteBean.isMatch())
                    return true;
            }
        }
        for(SpriteBean spriteBean : spriteExpeditionList)
        {
            if(spriteBean.isAttacker())
            {
                if(spriteBean.isBattleOrPrepare() || spriteBean.isMatch())
                    return true;
            }
        }
        return false;
    }


    public boolean isPeace()
    {
        return status == SGCommonProto.E_CITY_STATUS.CITY_STATUS_PEACE;
    }

    public boolean isBattle()
    {
        return status == SGCommonProto.E_CITY_STATUS.CITY_STATUS_BATTLE;
    }


    public SGCommonProto.CityItem parse()
    {
        SGCommonProto.CityItem.Builder data = SGCommonProto.CityItem.newBuilder();
        data.setId(id);
        data.setCamp(camp);
        data.setStatus(status);
        return data.build();
    }

    /**
     * 获取在城里的
     * @param team
     * @return
     */
    public List<SpriteBean> getNormalSpriteList(SGCommonProto.E_ARMY_TEAM team)
    {
        List<SpriteBean> teamList = new CopyOnWriteArrayList<>();

        if(team == SGCommonProto.E_ARMY_TEAM.ARMY_TEAM_DEF)
        {
            teamList.addAll(spriteGarrisonList);
        }

        for(SpriteBean spriteBean : spritePlayerList)
        {
            if((spriteBean.isRemove() && !spriteBean.isBattleOrPrepare()) || spriteBean.isDie())
                continue;

            if(spriteBean.getTeam() != team)
                continue;

            if(!spriteBean.isBattleOrPrepare() && !spriteBean.isMatch())
                continue;

            teamList.add(spriteBean);
        }

        for(SpriteBean spriteBean : spriteExpeditionList)
        {
            if((spriteBean.isRemove() && !spriteBean.isBattleOrPrepare()) || spriteBean.isDie())
                continue;

            if(spriteBean.getTeam() != team)
                continue;

            if(!spriteBean.isBattleOrPrepare() && !spriteBean.isMatch())
                continue;

            teamList.add(spriteBean);
        }

        return teamList;
    }


    public List<SGCommonProto.CommonObject> getArmyStatusCount(SGCommonProto.E_ARMY_TEAM team)
    {
        int queueCount = 0, battleCount = 0;
        List<SpriteBean> list = getNormalSpriteList(team);
        for(SpriteBean spriteBean : list)
        {
            if(spriteBean.isMatch())
                queueCount++;
            else if(spriteBean.isBattleOrPrepare())
                battleCount++;
        }

        List<SGCommonProto.CommonObject> result = new CopyOnWriteArrayList<>();
        result.add(SGCommonProto.CommonObject.newBuilder().setId(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH_VALUE).setValue(queueCount).build());
        result.add(SGCommonProto.CommonObject.newBuilder().setId(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_BATTLE_VALUE).setValue(battleCount).build());
        return result;
    }


    public List<SGCommonProto.CommonObject> parseArmyBaseList(SGCommonProto.E_ARMY_TEAM team)
    {
        List<SGCommonProto.CommonObject> list = new ArrayList<>();

        Map<Integer, Integer> map = new TreeMap<>();
        List<SpriteBean> teamList = getNormalSpriteList(team);

        for(SpriteBean bean : teamList)
        {
            if(map.get(bean.getCamp()) == null)
                map.put(bean.getCamp(), 1);
            else
                map.put(bean.getCamp(), map.get(bean.getCamp())+1);
        }

        for(Map.Entry<Integer, Integer> entry : map.entrySet())
        {
            list.add(SGCommonProto.CommonObject.newBuilder().setId(entry.getKey()).setValue(entry.getValue()).build());
        }

        return list;
    }

    /**
     * 获取路人
     * @return
     */
    public List<SpriteBean> getPasserbyList()
    {
        List<SpriteBean> result = new ArrayList<>();

        for(SpriteBean spriteBean : spritePlayerList)
        {
            if(spriteBean.isPasserby())
                result.add(spriteBean);
        }

        for(SpriteBean spriteBean : spriteExpeditionList)
        {
            if(spriteBean.isPasserby())
                result.add(spriteBean);
        }

        return result;
    }

    /**
     * 城详情获取列表(匹配状态也属于战斗)
     * @param team
     * @param spriteStatus
     * @return
     */
    public List<SpriteBean> getSpriteBeanList(SGCommonProto.E_ARMY_TEAM team, SGCommonProto.E_ARMY_STATUS spriteStatus)
    {
        List<SpriteBean> result = getNormalSpriteList(team);

        for(SpriteBean spriteBean : result)
        {
            if(spriteStatus == SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_BATTLE)
            {
                if(!spriteBean.isBattleOrPrepare())
                    result.remove(spriteBean);
            }
            else if(spriteBean.getStatus() != spriteStatus)
                result.remove(spriteBean);
        }

        return result;
    }



    public void dispatchWarn(String key, Object... params)
    {
        for(SpriteBean spriteBean : spritePlayerList)
        {
            if(spriteBean.isDie())
                continue;

            spriteBean.sendWarn(key, params);
        }
    }


    public void dispatchMsg(int code, byte[] data)
    {
//        LogUtils.debug("城　全员转发消息 masterPlayer -> " + masterPlayerIndex + "  code -> " + SGMainProto.E_MSG_ID.forNumber(code));

        for(SpriteBean spriteBean : spritePlayerList)
        {
            if(spriteBean.isDie() || spriteBean.isRemove())
            {
                if(code == SGMainProto.E_MSG_ID.MsgID_WorldMap_CityDetailInfo_VALUE)
                    continue;
            }

//            LogUtils.debug("=========================" + spriteBean.getObjectIndex());
            spriteBean.sendMsg(code, data);
        }

        sendToLookPlayer(code, data);
    }

    public void sendHegemonyChange(int code,byte[] data,boolean flag) {
        //获取 playerController的等级
        FunctionConfig functionConfig = DataFactory.getInstance().getGameObject(DataFactory.FUNCTION_KEY, FunctionFactory.WORLD_MAP_HEGEMONY);
        if (functionConfig == null){
            LogUtils.error("functionConfig is null functionId->" + FunctionFactory.WORLD_MAP_HEGEMONY);
            return;
        }
        int level = functionConfig.lv;
        for (SpritePlayerBean spriteBean : spritePlayerList){
            if (spriteBean.getPlayerController() != null) {
                //等级不足的玩家不通知争霸赛相关信息
                if (spriteBean.getPlayerController().getPlayer().getLv() < level)
                    continue;
                if (spriteBean.getPlayerController().getTcpConnection() != null) {
                    spriteBean.sendMsg(code, data);
                } else {
                    //处理离线玩家
                    spriteBean.getPlayerController().addIsHegemonyCache(flag);
                }
            }
        }
    }

    /**
     * 发给一个玩家 还是发给同阵营 或者发给所有玩家
     * @param code
     * @param data
     */
    public void sendCityDropMsg(int code,byte[] data,E_CityDropBelong_Status type,CityDropGroupConfig config,String... playerIndex) throws Exception{
        SGSystemProto.S2C_NotifyAlert.Builder response = null;
        String context = null;
        if (config != null){
            context = DataFactory.getInstance().getWord(config.localization);
            if (!StringUtils.isNullOrEmpty(context)){
                response = SGSystemProto.S2C_NotifyAlert.newBuilder();
                response.setType(SGCommonProto.E_NOTIFY_TYPE.NOTIFY_TYPE_WARN);
                response.setContent(context);
            }
        }
        for(SpritePlayerBean spriteBean : spritePlayerList){
            if (type == E_CityDropBelong_Status.CITY_DROP_PERSON){
                if (playerIndex[0].equals(spriteBean.getObjectIndex())){
                    spriteBean.sendMsg(code, data);
                    if (response != null){
                        //如果归属玩家个人的且玩家在战斗中 加入缓存中 连接回来
                        if (spriteBean.getPlayerController() != null){
                            if (spriteBean.getPlayerController().getTcpConnection() != null){
                                spriteBean.sendMsg(SGMainProto.E_MSG_ID.MsgID_System_NotifyAlert_VALUE,response.build().toByteArray());
                            }else{
                                spriteBean.getPlayerController().addSendMsgCache(context);
                            }
                        }
                    }
                }
            }
            if (type == E_CityDropBelong_Status.CITY_DROP_POWER){
                if (playerIndex[0].equals(spriteBean.getCamp())){
                    spriteBean.sendMsg(code, data);
                    if (response != null)
                        spriteBean.sendMsg(SGMainProto.E_MSG_ID.MsgID_System_NotifyAlert_VALUE,response.build().toByteArray());
                }
            }
            if (type == E_CityDropBelong_Status.CITY_DROP_ALL){
                spriteBean.sendMsg(code, data);
                if (response != null)
                    spriteBean.sendMsg(SGMainProto.E_MSG_ID.MsgID_System_NotifyAlert_VALUE,response.build().toByteArray());
            }
        }
    }

    public void dispatchMsg(int code, byte[] data, boolean isInCity, String... excludeIndex)
    {
        for(SpriteBean spriteBean : spritePlayerList)
        {
//            if(spriteBean.isDie())
//                continue;

            LogUtils.debug("code -> " + SGMainProto.E_MSG_ID.forNumber(code) + " isInCity -> " + isInCity + " spriteBean -> " + spriteBean);
            if(excludeIndex.length > 0 && spriteBean.getObjectIndex().equals(excludeIndex[0]))
                continue;

            if(spriteBean.isInCity() == isInCity)
                spriteBean.sendMsg(code, data);
        }

        sendToLookPlayer(code, data);
    }

    public void sendToLookPlayer(int code, byte[] data)
    {
//        if(code == SGMainProto.E_MSG_ID.MsgID_WorldMap_ChangeQueue_VALUE)
//        {
            WorldMapData worldMapData = WorldInfoFactory.getInstance().getWorldMapData(masterPlayerIndex);
            SpriteBean spriteBean = null;
            for(String playerIndex : lookPlayerList)
            {
                spriteBean = worldMapData.getPlayerActionBean(playerIndex);
                LogUtils.debug(id + "  通知正在查看这个城的玩家 -> " + playerIndex + "  " + spriteBean);
                if(spriteBean != null)
                    spriteBean.sendMsg(code, data);
            }
//        }
    }

//    public void testLook()
//    {
//        LogUtils.debug("city -> " + getConfig().name + "  look -> " + lookPlayerList);
//    }

    /**
     *
     * @param retreat 如果是撤退检测，则这个对象是撤退的玩家
     */
    public void checkCityStatus(SpriteBean... retreat)
    {
        if(status == SGCommonProto.E_CITY_STATUS.CITY_STATUS_BATTLE)
        {
            if(!isHaveAttacker())
            {
                LogUtils.debug("攻击方没有人了，城设置为和平");
                setStatus(SGCommonProto.E_CITY_STATUS.CITY_STATUS_PEACE);
            }
            else if(!isHaveDefender())
            {
                LogUtils.debug("防守方没人了,根据进城先后顺序，设置为占领中");
                SpriteBean winner = null;
                if(!spritePlayerList.isEmpty())
                    winner = spritePlayerList.get(0);
                else if(!spriteExpeditionList.isEmpty())
                    winner = spriteExpeditionList.get(0);

                if(winner != null)
                {
                    setOccupyCityParam(new OccupyCityParam(DataFactory.currentTime, camp, winner, retreat.length>0?retreat[0]:null));
                    setStatus(SGCommonProto.E_CITY_STATUS.CITY_STATUS_TRANSITION);
                }
                else
                {
                    LogUtils.error("数据异常,防御方没有人,攻击方也没有人 -> " + this);
                    setStatus(SGCommonProto.E_CITY_STATUS.CITY_STATUS_PEACE);
                }
            }
        }
//        LogUtils.debug("检测城状态后再检测防守方状态");
//        checkDefStatus();
    }

    /**
     * 获取城内总队伍数量(包含路人)
     * @return
     */
    public int getTotalArmyCount(SGCommonProto.E_ARMY_TEAM team)
    {
        int result = 0;
        for(SpriteBean spriteBean : spritePlayerList)
        {
            if(spriteBean.getTeam() != team)
                continue;
            result++;
        }

        for(SpriteBean spriteBean : spriteExpeditionList)
        {
            if(spriteBean.getTeam() != team)
                continue;
            result++;
        }

        if(team == SGCommonProto.E_ARMY_TEAM.ARMY_TEAM_DEF)
        {
            result += spriteGarrisonList.size();
        }
        return result;
    }


    /**
     * 发送占领城的信息
     */
    public void sendOccupyInfo(OccupyCityParam occupyCityParam)
    {
        String str1 = "", str2 = "";

        SGPlayerProto.S2C_ChatMsg.Builder response = null;

        WorldMapData worldMapData = WorldInfoFactory.getInstance().getWorldMapData(masterPlayerIndex);
        for(CityBean cityBean : worldMapData.getCityMap().values())
        {
            for(SpritePlayerBean spriteBean : cityBean.getSpritePlayerList())
            {
                if(!spriteBean.isCanSendMsg())
                    continue;

                if(spriteBean.camp != occupyCityParam.getBeforeCamp() && spriteBean.camp != occupyCityParam.getWinner().camp)
                    continue;

                LogUtils.debug(spriteBean.getName() + " " + spriteBean.getCamp() + "   通知城占领 -> " + occupyCityParam);

                if(spriteBean.getCamp() == occupyCityParam.getWinner().getCamp())
                    str1 = WordFactory.getWord(WordFactory.MAP_MYSELF);
                else
                    str1 = WordFactory.getCampStr(occupyCityParam.getWinner().getCamp());

                if(spriteBean.getCamp() == occupyCityParam.getBeforeCamp())
                    str2 = WordFactory.getWord(WordFactory.MAP_MYSELF);
                else
                    str2 = WordFactory.getCampStr(occupyCityParam.getBeforeCamp());

                response = SGPlayerProto.S2C_ChatMsg.newBuilder();
                response.setChatItem(SendUtils.createChatItem("", WordFactory.getWord(WordFactory.MAP_OCCUPY_CITY_INFO, str1, WordFactory.getWord(WordFactory.NOTICE_GREEN, occupyCityParam.getWinner().getName()), str2, getConfig().name), SGCommonProto.E_CHAT_TYPE.CHAT_TYPE_BATTLE));

                LogUtils.debug("chatItem -> " + response);
                spriteBean.sendMsg(SGMainProto.E_MSG_ID.MSGID_Player_ChatMsg_VALUE, response.build().toByteArray());
            }
        }
    }

    /**
     * 检查防守方的状态
     */
    private void checkDefStatus()
    {
        if(status == SGCommonProto.E_CITY_STATUS.CITY_STATUS_BATTLE)
        {
            for(SpriteBean bean : spritePlayerList)
            {
                if(bean.isRemove() || bean.isDie())
                    continue;

                if(bean.isDefender() && bean.isFree())
                {
                    LogUtils.debug("防守方 -> " + bean.getName() + "  设置为待命 城状态 ->" + status);
                    bean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_WAIT);
                }
            }
            for(SpriteBean bean : spriteExpeditionList)
            {
                if(bean.isRemove() || bean.isDie())
                    continue;

                if(bean.isDefender() && bean.isFree())
                {
                    LogUtils.debug("防守方 -> " + bean.getName() + "  设置为待命 城状态 ->" + status);
                    bean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_WAIT);
                }
            }
        }
        else if(status == SGCommonProto.E_CITY_STATUS.CITY_STATUS_PEACE)
        {
            for(SpriteBean bean : spritePlayerList)
            {
                if(bean.isRemove() || bean.isDie())
                    continue;

                if(bean.isDefender() && (bean.isMatch() || bean.isWait()))
                {
                    LogUtils.debug("防守方 -> " + bean.getName() + "  设置为空闲 城状态 ->" + status);
                    bean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_FREE);
                }
            }
            for(SpriteBean bean : spriteExpeditionList)
            {
                if(bean.isRemove() || bean.isDie())
                    continue;

                if(bean.isDefender() && (bean.isMatch() || bean.isWait()))
                {
                    LogUtils.debug("防守方 -> " + bean.getName() + "  设置为空闲 城状态 ->" + status);
                    bean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_FREE);
                }
            }
        }
    }

    public void setStatus(SGCommonProto.E_CITY_STATUS status)
    {
        if(this.status == status)
            return;

        SGCommonProto.E_CITY_STATUS beforeStatus = this.status;

        this.status = status;

        if(status == SGCommonProto.E_CITY_STATUS.CITY_STATUS_PEACE)
        {
            initGarrison(E_CityInitGarrisonType.STATUS_PEACE);

            for(SpriteExpeditionBean spriteBean : spriteExpeditionList)
            {
                if(!spriteBean.isEndRoute())
                {
                    //城变为和平，远征军重新设置为移动
                    spriteBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MOVE);
                }
            }
        }

        SendUtils.sendCityStatus(this, beforeStatus);

        this.lastUpdateStatusTime = DataFactory.currentTime == 0 ? System.currentTimeMillis() : DataFactory.currentTime;
    }

    /**
     * 有玩家来查看这个城了
     * @param playerIndex
     */
    public void addLookPlayer(String playerIndex)
    {
        if(lookPlayerList.contains(playerIndex))
            return;

        LogUtils.debug("添加查看玩家 ----------" + playerIndex + "  " + id);
        lookPlayerList.add(playerIndex);
    }

    public void removeLookPlayer(String playerIndex)
    {
        LogUtils.debug("删除查看玩家 -------------" + playerIndex + "   " + id);
        lookPlayerList.remove(playerIndex);
    }

    public List<String> getLookSpriteBeanList()
    {
        return lookPlayerList;
    }

    public void removeSprite(SpriteBean spriteBean, E_CityInOutType type)
    {
        if(spriteBean instanceof SpriteGarrisonBean)
            spriteGarrisonList.remove(spriteBean);
        else if(spriteBean instanceof SpritePlayerBean)
            spritePlayerList.remove(spriteBean);
        else if(spriteBean instanceof SpriteExpeditionBean)
            spriteExpeditionList.remove(spriteBean);

        spriteBeanMap.remove(spriteBean.getObjectIndex());

        removeLookPlayer(spriteBean.getObjectIndex());

        WorldInfoFactory.getInstance().addInOutCityRecord(getConfig().name, spriteBean.getObjectIndex()+"-"+spriteBean.getName(), type, !Utils.isNull(masterPlayerIndex));
    }


    public void stopServerCheckOccupy()
    {
        if(occupyCityParam != null)
        {
            this.camp = occupyCityParam.getWinner().camp;
        }
    }


    /**
     *　检查异常数据
     */
    public void checkErrorData()
    {
        String cityName = getConfig().name;
        LogUtils.warn("检测城 -> " + cityName + " 的异常数据");
        if(!isHaveAttacker())
        {
            LogUtils.warn(" 攻击方没有人!");
            if(status == SGCommonProto.E_CITY_STATUS.CITY_STATUS_BATTLE)
            {
                LogUtils.warn("城状态为交战，修复成和平");
                setStatus(SGCommonProto.E_CITY_STATUS.CITY_STATUS_PEACE);
            }

            if(status == SGCommonProto.E_CITY_STATUS.CITY_STATUS_PEACE)
            {
                for(SpritePlayerBean spritePlayerBean : spritePlayerList)
                {
                    if(spritePlayerBean.isDefender() && !spritePlayerBean.isDie())
                    {
                        LogUtils.warn("防御方 -> " + spritePlayerBean.getName() + " 修复成空闲状态");
                        spritePlayerBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_FREE);
                    }
                }
                for(SpriteGarrisonBean spriteGarrisonBean : spriteGarrisonList)
                {
                    spriteGarrisonBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH);
                }
                for(SpriteExpeditionBean spriteExpeditionBean : spriteExpeditionList)
                {
                    spriteExpeditionBean.setStatus(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH);
                }
            }
        }
        else
        {
            if(!isHaveDefender())
            {
                LogUtils.warn("没有防御方的城 -> 设置为和平!");
                setStatus(SGCommonProto.E_CITY_STATUS.CITY_STATUS_PEACE);
            }
            else
            {
                if(status == SGCommonProto.E_CITY_STATUS.CITY_STATUS_PEACE)
                {
                    LogUtils.warn("有攻击方并且也有防御方的城 -> 设置为交战!");
                    setStatus(SGCommonProto.E_CITY_STATUS.CITY_STATUS_BATTLE);
                }
            }

            if(status == SGCommonProto.E_CITY_STATUS.CITY_STATUS_PEACE)
            {
                for(SpritePlayerBean spritePlayerBean : spritePlayerList)
                {
                    if(spritePlayerBean.isAttacker() && !spritePlayerBean.isDie())
                    {
                        LogUtils.warn("和平城　-> 删除攻击方 -> " + spritePlayerBean.getName());
                        WorldInfoFactory.getInstance().getWorldMapData(masterPlayerIndex).removeSprite(spritePlayerBean, this, false, E_CityInOutType.OUT_ERROR);
                        checkCityStatus(spritePlayerBean);
                    }
                }
            }
        }
    }


    public void sendDetailInfo(SGCommonProto.E_CITY_STATUS beforeStatus)
    {
        List<PlayerController> attackerList = new ArrayList<>();
        List<PlayerController> defenderList = new ArrayList<>();
        for(SpritePlayerBean spritePlayerBean : spritePlayerList)
        {
            if(!spritePlayerBean.isInCity() || spritePlayerBean.isRemove())
                continue;

            if(!spritePlayerBean.isCanSendMsg())
                continue;

            if(spritePlayerBean.isAttacker())
                attackerList.add(spritePlayerBean.getPlayerController());
            else if(spritePlayerBean.isDefender())
                defenderList.add(spritePlayerBean.getPlayerController());
        }

        if(status == SGCommonProto.E_CITY_STATUS.CITY_STATUS_BATTLE)
        {
            SendUtils.sendCityDetailInfo(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH, SGCommonProto.E_ARMY_TEAM.AMRY_TEAM_ALL, this, true, true, true, false, attackerList.toArray());
            SendUtils.sendCityDetailInfo(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH, SGCommonProto.E_ARMY_TEAM.AMRY_TEAM_ALL, this, true, false, true, true, defenderList.toArray());}
        else
        {
            SendUtils.sendCityDetailInfo(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH, SGCommonProto.E_ARMY_TEAM.AMRY_TEAM_ALL, this, true, true, false, false, attackerList.toArray());
            SendUtils.sendCityDetailInfo(SGCommonProto.E_ARMY_STATUS.ARMY_STATUS_MATCH, SGCommonProto.E_ARMY_TEAM.AMRY_TEAM_ALL, this, true, false, false, true, defenderList.toArray());
        }
    }

    public boolean isGarrisonRefreshing() {
        return garrisonRefreshing;
    }

    public void setGarrisonRefreshing(boolean garrisonRefreshing) {
        this.garrisonRefreshing = garrisonRefreshing;
    }

    public SGCommonProto.E_CITY_STATUS getStatus() {
        return status;
    }

    public void setOccupyCityParam(OccupyCityParam occupyCityParam) {
        this.occupyCityParam = occupyCityParam;
    }

    public OccupyCityParam getOccupyCityParam() {
        return occupyCityParam;
    }

    public List<SpriteGarrisonBean> getSpriteGarrisonList() {
        return spriteGarrisonList;
    }

    public List<SpriteExpeditionBean> getSpriteExpeditionList() {
        return spriteExpeditionList;
    }


    public List<SpritePlayerBean> getSpritePlayerList() {
        return spritePlayerList;
    }

    public CityDropData getCityDropData() {
        return cityDropData;
    }

    public void setCityDropData(CityDropData cityDropData) {
        this.cityDropData = cityDropData;
    }

    public String getMasterPlayerIndex() {
        return masterPlayerIndex;
    }

    public long getLastUpdateStatusTime() {
        return lastUpdateStatusTime;
    }

    @Override
    public CityConfig getConfig() {
        return (CityConfig) super.getConfig();
    }

    private String toListString()
    {
        StringBuilder buffer = new StringBuilder();
        for(SpritePlayerBean spritePlayerBean : spritePlayerList)
        {
            buffer.append("{objectIndex=");
            buffer.append(spritePlayerBean.getObjectIndex());
            buffer.append(",name=");
            buffer.append(spritePlayerBean.getName());
            buffer.append(",status=");
            buffer.append(spritePlayerBean.getStatus());
            buffer.append(",team");
            buffer.append(spritePlayerBean.getTeam());
            buffer.append("}");
        }
        return buffer.toString();
    }


    @Override
    public String toString() {
        return "{" +
                "masterPlayerIndex='" + masterPlayerIndex + '\'' +
                ", garrisonRefreshing=" + garrisonRefreshing +
                ", status=" + status +
                ", camp=" + camp +
                ", spriteGarrisonList=" + spriteGarrisonList +
                ", spritePlayerList=" + spritePlayerList +
                ", spriteExpeditionList=" + spriteExpeditionList +
                ", lookPlayerList=" + lookPlayerList +
                "}-" + super.toString();
    }
}
